#pragma once

#include <string>
#include <iostream>
#include <functional>
#include <cstring>
#include <cstdlib>
#include <sys/epoll.h>
#include "Log.hpp"
#include "Err.hpp"

class Epoll
{
    const static int gsize = 128;
    const static int defaultfd = -1;

public:
    Epoll() : epfd_(defaultfd)
    {
    }

    void Create()
    {
        epfd_ = epoll_create(gsize);
        if (epfd_ < 0)
        {
            logMessage(Fatal, "epoll create error:%s [code:]", strerror(errno), errno);
            exit(EPOLL_CREATE_ERR);
        }
        logMessage(Info, "epoll create successfully!");
    }

    // 用户告诉内核
    bool AddEvent(int fd, uint32_t events)
    {
        struct epoll_event ev;
        ev.data.fd = fd;
        ev.events = events; // 用户数据, epoll底层不对该数据做任何修改，就是为了给未来就绪返回的！
        int ret = epoll_ctl(epfd_, EPOLL_CTL_ADD, fd, &ev);
        if (ret < 0)
        {
            logMessage(Warning, "fd:%d epoll_ctl add event error:%s [code:%d]", fd,strerror(errno), errno);
            return false;
        }
        logMessage(Info, "Add event successfully!");
        return true;
    }

    bool Mod(int fd, uint32_t events)
    {
        struct epoll_event ev;
        ev.data.fd = fd;
        ev.events = events;
        int ret = epoll_ctl(epfd_, EPOLL_CTL_MOD, fd, &ev);
        if (ret < 0)
        {
            logMessage(Warning, "fd:%d epoll_ctl mod event error:%s [code:%d]", fd,strerror(errno), errno);
            return false;
        }
        logMessage(Info, "Mod event successfully!");
        return true;
    }

    bool DelEvent(int fd)
    {
        // 传入的fd是合法的
        int ret = epoll_ctl(epfd_, EPOLL_CTL_DEL, fd, nullptr);
        if (ret < 0)
        {
            logMessage(Warning, "epoll_ctl delete event error:%s [code:%d]", strerror(errno), errno);
            return false;
        }
        logMessage(Info, "epoll delete event successfully!");
        return true;
    }

    int Wait(struct epoll_event *envs, int num, int timeout)
    {
        return epoll_wait(epfd_, envs, num, timeout);
    }

    int Fd()
    {
        return epfd_;
    }

    void Close()
    {
        if (epfd_ != defaultfd)
            close(epfd_);
        logMessage(Info, "epollfd close ...");
    }

    ~Epoll() {}

private:
    int epfd_;
};